package com.example.demo.util;

import com.sun.jmx.snmp.ThreadContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * *  Author:A
 * *  2020/8/14 17:21
 **/
public class CommonThread extends Thread implements Callable<CommonThread> {
    private static final Map<String, ExecutorService> threadPool = new ConcurrentHashMap<String, ExecutorService>();
    private static final AtomicInteger threadId = new AtomicInteger();

    private static final int POOL_SIZE = 20;

    private String poolName;
    private String resultKey;
    ThreadContext context;
    ThreadContext currentContext;

    protected Object callReuslt;


    private ExecutorService pool;

    public CommonThread() {
        this("albert-thread-" + threadId.incrementAndGet());
    }

    public CommonThread(String name) {
        this(name, null);
    }

    public CommonThread(String name, String poolName) {
        super(name);
        super.setDaemon(true);
        if (poolName == null) {
            poolName = "base";
        }
        this.poolName = poolName;
        pool = threadPool.get(poolName);
        if (pool == null) {
            synchronized (threadPool) {
                pool = threadPool.get(poolName);
                if (pool == null) {
                    //可以读取位置
                    Integer poolSize = POOL_SIZE;
                    final String tempPoolName = poolName;
                    pool = new ThreadPoolExecutor(poolSize, poolSize, 10L, TimeUnit.SECONDS,
                            new LinkedBlockingDeque<Runnable>(), new ThreadFactory() {
                        int index = 0;

                        @Override
                        public Thread newThread(Runnable r) {
                            return new Thread(r, String.format("albert:%s-%4d", tempPoolName, (++index)));
                        }
                    });
                    ((ThreadPoolExecutor) pool).allowCoreThreadTimeOut(true);
                    threadPool.put(poolName, pool);
                }
            }
        }
        this.context = ThreadContext.getThreadContext();
    }

    public CommonThread resultMapping(String resultKey) {
        this.resultKey = resultKey;
        return this;
    }

    //子线程
    static Map<String, List<Future<CommonThread>>> childResultMap = new HashMap<String, List<Future<CommonThread>>>();

    @Override
    public void start() {
        if (resultKey != null) {
            List<Future<CommonThread>> resultList = childResultMap.get(resultKey);
            if (resultList == null) {
                synchronized (childResultMap) {
                    resultList = childResultMap.get(resultKey);
                    if (resultList == null) {
                        resultList = new ArrayList<>();
                        childResultMap.put(resultKey, resultList);
                    }
                }
            }
            resultList.add(pool.submit((Callable) this));
        } else {
            pool.execute(this);
        }
    }

    @Override
    public CommonThread call() throws Exception {
        this.currentContext = context;
        run();
        return this;
    }

    public <T> List<T> getResults(String resultKey) {
        List<Future<CommonThread>> resultList = childResultMap.get(resultKey);
        if (resultList == null) {
            return null;
        }
        List<T> results = new ArrayList<T>();
        for (Future<CommonThread> f : resultList) {
            try {
                results.add((T) f.get().callReuslt);
            } catch (InterruptedException | ExecutionException e) {
                results.add(null);
            }
        }
        resultList.clear();
        childResultMap.remove(resultKey);
        return results;
    }
}
